package com.alibaba.otter.node.etl.autoconfigure;

import com.alibaba.otter.node.common.config.ConfigClientService;
import com.alibaba.otter.node.common.config.NodeTaskService;
import com.alibaba.otter.node.etl.OtterController;
import com.alibaba.otter.node.etl.common.datasource.DataSourceService;
import com.alibaba.otter.node.etl.common.db.dialect.DbDialectFactory;
import com.alibaba.otter.node.etl.common.jmx.StageAggregationCollector;
import com.alibaba.otter.shared.arbitrate.ArbitrateEventService;
import com.alibaba.otter.shared.arbitrate.ArbitrateManageService;
import com.alibaba.otter.shared.common.utils.thread.ExecutorServiceFactoryBean;
import com.alibaba.otter.shared.common.utils.thread.ExecutorTemplate;
import com.alibaba.otter.shared.common.utils.thread.ExecutorTemplateGetter;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.CommonsPool2TargetSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import java.util.concurrent.ExecutorService;

@Configuration(proxyBeanMethods = false)
public class NodeCommonAutoConfiguration {


    @Bean
    public ExecutorServiceFactoryBean executorService() {
        ExecutorServiceFactoryBean executorServiceFactoryBean = new ExecutorServiceFactoryBean();
        executorServiceFactoryBean.setPoolSize(100);
        executorServiceFactoryBean.setAcceptCount(200);
        executorServiceFactoryBean.setName("Otter-Seda-Executor");
        return executorServiceFactoryBean;
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public ExecutorTemplate executorTemplateTarget() {
        ExecutorTemplate executorTemplate = new ExecutorTemplate();
        executorTemplate.setPoolSize(5);
        return executorTemplate;
    }

    @Bean
    public CommonsPool2TargetSource executorTemplateTargetSource() {
        CommonsPool2TargetSource commonsPool2TargetSource = new CommonsPool2TargetSource();

        commonsPool2TargetSource.setMinIdle(1);
        commonsPool2TargetSource.setMaxSize(-1);
        commonsPool2TargetSource.setTimeBetweenEvictionRunsMillis(60000);
        commonsPool2TargetSource.setMinEvictableIdleTimeMillis(60000);
        commonsPool2TargetSource.setTargetBeanName("executorTemplateTarget");

        return commonsPool2TargetSource;
    }

    @Bean
    public ExecutorTemplateGetter executorTemplateGetter(@Qualifier("executorTemplateTargetSource") CommonsPool2TargetSource executorTemplateTargetSource) {
        return new ExecutorTemplateGetter(executorTemplateTargetSource);
    }

    @Bean
    public ProxyFactoryBean executorTemplate(@Qualifier("executorTemplateTargetSource") CommonsPool2TargetSource executorTemplateTargetSource) {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setOptimize(false);
        proxyFactoryBean.setProxyTargetClass(true);
        proxyFactoryBean.setTargetSource(executorTemplateTargetSource);
        return proxyFactoryBean;
    }

    /**
     * TODO jmx
     */
    @Bean
    public StageAggregationCollector stageAggregationCollector() {
        return new StageAggregationCollector();
    }

    @Bean(initMethod = "start")
    public OtterController otterController(ConfigClientService configClientService,
                                           ArbitrateManageService arbitrateManageService,
                                           NodeTaskService nodeTaskService,
                                           DataSourceService dataSourceService,
                                           DbDialectFactory dbDialectFactory,
                                           ArbitrateEventService arbitrateEventService,
                                           @Qualifier("executorService") ExecutorService executorService,
                                           StageAggregationCollector stageAggregationCollector) {
        OtterController controller = new OtterController();
        controller.setConfigClientService(configClientService);
        controller.setArbitrateManageService(arbitrateManageService);
        controller.setNodeTaskService(nodeTaskService);
        controller.setDataSourceService(dataSourceService);
        controller.setDbDialectFactory(dbDialectFactory);
        controller.setArbitrateEventService(arbitrateEventService);
        controller.setExecutorService(executorService);
        controller.setStageAggregationCollector(stageAggregationCollector);
        return controller;
    }
}
